package com.hiultra.archive.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hiultra.archive.domain.*;
import com.hiultra.archive.domain.vo.ArchiveStocktakingTaskIssuedVo;
import com.hiultra.archive.domain.vo.ArchiveStocktakingTaskReportVo;
import com.hiultra.archive.domain.vo.ResultEntity;
import com.hiultra.archive.mapper.ArchiveStocktakingTaskMapper;
import com.hiultra.archive.service.*;
import com.hiultra.archive.utils.sgsm.SM2Util;
import com.hiultra.archive.utils.tool.ToolUtils;
import com.hiultra.common.constant.BusinessConstants;
import com.hiultra.common.exception.ServiceException;
import com.hiultra.common.utils.DateUtils;
import com.hiultra.common.utils.uuid.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.net.URISyntaxException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 盘点任务Service业务层处理
 *
 * @author paidaxing
 * @date 2024-07-31
 */
@Service
public class ArchiveStocktakingTaskServiceImpl implements IArchiveStocktakingTaskService {
    @Autowired
    private ArchiveStocktakingTaskMapper archiveStocktakingTaskMapper;
    @Value("${roomNo}")
    private String roomNo;
    @Autowired
    private IArchiveStocktakingBoxService archiveStocktakingBoxService;
    @Autowired
    private IArchiveStocktakingService archiveStocktakingService;
    @Autowired
    private IArcBoxService arcBoxService;
    @Autowired
    private IRoomArchiveService roomArchiveService;
    @Autowired
    private IArchiveArchAreaService archiveArchAreaService;
    @Autowired
    private IArchiveCabinetService archiveCabinetService;

    @Value("${priKey}")
    private String priKey;
    @Value("${pubKey}")
    private String pubKey;
    @Value("${urlIp}")
    private String urlIp;
    @Value("${archiveStocktakingTaskResultReportUrl}")
    private String archiveStocktakingTaskResultReportUrl;

    private static final Logger log = LoggerFactory.getLogger(ArchiveStocktakingTaskServiceImpl.class);

    /**
     * 查询盘点任务
     *
     * @param taskId 盘点任务主键
     * @return 盘点任务
     */
    @Override
    public ArchiveStocktakingTask selectArchiveStocktakingTaskByTaskId(String taskId) {
        return archiveStocktakingTaskMapper.selectArchiveStocktakingTaskByTaskId(taskId);
    }

    /**
     * 通过单号查询盘点任务
     *
     * @return 盘点任务
     * @paraminventoryNo 盘点任务单号
     */
    @Override
    public ArchiveStocktakingTask selectArchiveStocktakingTaskByTaskNo(String inventoryNo) {
        return archiveStocktakingTaskMapper.selectArchiveStocktakingTaskByTaskNo(inventoryNo);
    }

    /**
     * 查询盘点任务列表
     *
     * @param archiveStocktakingTask 盘点任务
     * @return 盘点任务
     */
    @Override
    public List<ArchiveStocktakingTask> selectArchiveStocktakingTaskList(ArchiveStocktakingTask archiveStocktakingTask) {

        return archiveStocktakingTaskMapper.selectArchiveStocktakingTaskList(archiveStocktakingTask);
    }

    /**
     * 新增盘点任务
     *
     * @param archiveStocktakingTask 盘点任务
     * @return 结果
     */
    @Override
    public int insertArchiveStocktakingTask(ArchiveStocktakingTask archiveStocktakingTask) {
        archiveStocktakingTask.setCreateTime(DateUtils.getNowDate());
        return archiveStocktakingTaskMapper.insertArchiveStocktakingTask(archiveStocktakingTask);
    }

    /**
     * 修改盘点任务
     *
     * @param archiveStocktakingTask 盘点任务
     * @return 结果
     */
    @Override
    public int updateArchiveStocktakingTask(ArchiveStocktakingTask archiveStocktakingTask) {
        return archiveStocktakingTaskMapper.updateArchiveStocktakingTask(archiveStocktakingTask);
    }

    /**
     * 批量删除盘点任务
     *
     * @param taskIds 需要删除的盘点任务主键
     * @return 结果
     */
    @Override
    public int deleteArchiveStocktakingTaskByTaskIds(String[] taskIds) {
        return archiveStocktakingTaskMapper.deleteArchiveStocktakingTaskByTaskIds(taskIds);
    }

    /**
     * 删除盘点任务信息
     *
     * @param taskId 盘点任务主键
     * @return 结果
     */
    @Override
    public int deleteArchiveStocktakingTaskByTaskId(String taskId) {
        return archiveStocktakingTaskMapper.deleteArchiveStocktakingTaskByTaskId(taskId);
    }

    /**
     * 档案盘点上报
     */
    @Override
    public int archiveStocktakingTaskResultReport(ArchiveStocktakingTask archiveStocktakingTask) throws URISyntaxException, JsonProcessingException {
        //查询档案盘点任务信息
        ArchiveStocktakingTask archiveStocktakingTaskN = archiveStocktakingTaskMapper.selectArchiveStocktakingTaskByTaskId(archiveStocktakingTask.getTaskId());
        if (null == archiveStocktakingTaskN) {
            throw new ServiceException("不存在此工单任务，请检查后重试！");
        }
        //判断工单推送状态，如果已经推送了就不能重复推送了
        if (BusinessConstants.END_PUSHSTATUS.equals(archiveStocktakingTaskN.getPushStatus())) {
            throw new ServiceException("工单编号为" + archiveStocktakingTaskN.getInventoryNo() + "已经提交推送！请检查重试！");
        }
        //档案盒-详情信息
        List<ArchiveStocktakingBox> archiveStocktakingBoxList = archiveStocktakingBoxService.selectArchiveStocktakingBoxListReport(new ArchiveStocktakingBox() {{
            setTaskId(archiveStocktakingTaskN.getTaskId());setInventoryResult(BusinessConstants.INVENTORY_RESULT_LOSS);
        }});

        //判断档案柜是否存在
        if (ObjectUtil.isEmpty(archiveStocktakingBoxList)) {
            throw new ServiceException("工单编号为" + archiveStocktakingTaskN.getInventoryNo() + "无可上报信息！请检查重试！");
        }

        //档案柜入参
        List<ArchiveStocktakingTaskReportVo.ArchiveCabinet> cabinetList = new ArrayList<>();
        // 按照 ArchiveStocktakingBox.getColNo() 方法返回值对对象进行分组
        List<String> colNoList = new ArrayList<>();

        //传参档案柜
        Map<String, ArchiveStocktakingTaskReportVo.ArchiveCabinet> archiveCabinetMap = new HashMap<>();

        //遍历查询的档案柜信息
        for (ArchiveStocktakingBox archiveStocktakingBox : archiveStocktakingBoxList) {

            String cabinetId = archiveStocktakingBox.getCabinetId();
            ArchiveStocktakingTaskReportVo.ArchiveCabinet archiveCabinet = archiveCabinetMap.get(cabinetId) == null
                    ? new ArchiveStocktakingTaskReportVo.ArchiveCabinet()
                    : archiveCabinetMap.get(cabinetId);
            List<ArchiveStocktakingTaskReportVo.ArchiveBox> boxList = ObjectUtil.isEmpty(archiveCabinet.getBoxList())
                    ? new ArrayList<>()
                    : archiveCabinet.getBoxList();

            //查询档案盒档案
            List<ArchiveStocktaking> archiveStocktakingList = archiveStocktakingService.selectArchiveStocktakingListReport(new ArchiveStocktaking() {{
                setTaskBoxId(archiveStocktakingBox.getId());setInventoryResult("01");
            }});

            //转换成传参对象
            List<ArchiveStocktakingTaskReportVo.Archive> archiveList = JSON.parseArray(JSON.toJSONString(archiveStocktakingList), ArchiveStocktakingTaskReportVo.Archive.class);

            //档案信息添加
            ArchiveStocktakingTaskReportVo.ArchiveBox archiveBox = new ArchiveStocktakingTaskReportVo.ArchiveBox();
            archiveBox.setBoxId(archiveStocktakingBox.getBoxId());
            archiveBox.setBoxNo(archiveStocktakingBox.getBoxNo());
            archiveBox.setBoxBarCode(archiveStocktakingBox.getBoxBarCode());
            archiveBox.setInventoryResult(archiveStocktakingBox.getInventoryResult());
            archiveBox.setAddStatus(archiveStocktakingBox.getAddStatus());
            archiveBox.setActualHouseLocationNo(archiveStocktakingBox.getActualHouseLocationNo());
            archiveBox.setMissStatus(archiveStocktakingBox.getMissStatus());
            archiveBox.setHouseLocationNo(archiveStocktakingBox.getHouseLocationNo());
            archiveBox.setInventoryStatus(archiveStocktakingBox.getInventoryStatus());
            archiveBox.setArchiveList(archiveList);
            boxList.add(archiveBox);

            //添加档案柜
            if (StrUtil.isBlank(archiveCabinet.getCabinetId())) {
                //档案柜编号
                archiveCabinet.setCabinetId(cabinetId);
            }
            archiveCabinet.setBoxList(boxList);
            archiveCabinetMap.put(cabinetId, archiveCabinet);

        }

        ArchiveStocktakingTaskReportVo archiveStocktakingTaskReportVo = ToolUtils.convertEntity(archiveStocktakingTaskN, ArchiveStocktakingTaskReportVo::new);

        archiveStocktakingTaskReportVo.setCabinetList(new ArrayList<>(archiveCabinetMap.values()));

        // 将JsonData对象转换为JSON字符串
        String jsonString = new ObjectMapper().writeValueAsString(archiveStocktakingTaskReportVo);
        System.out.println("盘点上报入参" + jsonString);

        //发送请求获取数据
        HashMap hashMap = ToolUtils.sendPostRequest(BusinessConstants.ARCHIVE_STOCKTAKING_TASK_REPORT_NO, urlIp, archiveStocktakingTaskResultReportUrl, "档案盘点任务结果", jsonString, pubKey, priKey);
        //判断是否成功
        if (hashMap == null || !hashMap.containsKey("code") || !hashMap.get("code").equals("00000")) {
            System.out.println("档案盘点任务上传结果失败");
            throw new ServiceException(hashMap.get("message").toString());
        }
        System.out.println("档案盘点任务上报结果成功");
        archiveStocktakingTaskN.setPushStatus(BusinessConstants.END_PUSHSTATUS);

        return updateArchiveStocktakingTask(archiveStocktakingTaskN);
    }

    /**
     * 盘点移位任务下发接口
     *
     * @param data
     * @return 结果
     */
    @Override
    public ResultEntity insertIssuedArchiveStocktakingTask(String data) throws ParseException {
        //解密
        System.out.println("盘点移位任务下发数据：" + data);
        String decryptedResult = new SM2Util().decryptBySM2(data, priKey);
        System.out.println("盘点移位任务下发解密结果：" + decryptedResult);
        ArchiveStocktakingTaskIssuedVo archiveStocktakingTaskIssuedVo = JSON.parseObject(decryptedResult.trim(), ArchiveStocktakingTaskIssuedVo.class);

        if (ObjectUtil.isNull(archiveStocktakingTaskIssuedVo)) {
            // 返回错误信息或抛出异常
            log.info("入参解析出错，请检查重试");
            return ResultEntity.error("入参解析出错，请检查重试");
        }
        try {
            processStocktakingTask(archiveStocktakingTaskIssuedVo);
        } catch (ServiceException e) {
            e.printStackTrace();
            return ResultEntity.error(e.getMessage());
        }

        return ResultEntity.success();
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void processStocktakingTask(ArchiveStocktakingTaskIssuedVo archiveStocktakingTaskIssuedVo) throws ParseException {
        try {
            List<ArchiveStocktakingBox> archiveStocktakingBoxList = new ArrayList<>();
            List<ArchiveStocktaking> archiveStocktakingList = new ArrayList<>();
            if (ObjectUtil.isNotNull(archiveStocktakingTaskIssuedVo)) {
                //根据盘点单生成盘点详情
                //先插入盘点任务表
                //判断数据是否存在
                ArchiveStocktakingTask archiveStocktakingTaskIs = selectArchiveStocktakingTaskByTaskNo(archiveStocktakingTaskIssuedVo.getInventoryNo());
                if (null == archiveStocktakingTaskIs) {
                    ArchiveStocktakingTask archiveStocktakingTask = ToolUtils.convertEntity(archiveStocktakingTaskIssuedVo, ArchiveStocktakingTask::new);
                    archiveStocktakingTask.setTaskId(UUID.randomUUID().toString().replace("-", ""));
                    DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
                    Date parsedDate = dateFormat.parse(archiveStocktakingTaskIssuedVo.getInventoryDate());
                    archiveStocktakingTask.setInventoryDate(parsedDate);
                    archiveStocktakingTask.setPushStatus(BusinessConstants.PUSHSTATUS);
                    //设置盘点状态
                    archiveStocktakingTask.setStatus(BusinessConstants.PRE_INVENTORY_ORDER_STATUS);
                    insertArchiveStocktakingTask(archiveStocktakingTask);
                    for (ArchiveStocktakingTaskIssuedVo.ArchiveCabinet cabinet : archiveStocktakingTaskIssuedVo.getCabinetList()) {
                        //根据档案柜信息查询
                        ArcBox arcBoxQuery = new ArcBox();
                        //映射no
                        //通过id查询no roomId配置文件中配置

                        //arcBoxQuery.setRoomNo(roomNo);
                        //通过areaId查询no
                        ArchiveArchArea archiveArchArea = archiveArchAreaService.selectArchiveArchAreaById(cabinet.getAreaId());
                        //判空
                        if (ObjectUtil.isNull(archiveArchArea)) {
                            log.info("未查询到档案区标识" + cabinet.getAreaId() + "信息,请检查下发数据是否正确！");
                            throw new ServiceException("未查询到档案区标识" + cabinet.getAreaId() + "信息，请检查下发数据是否正确！");
                        }

                        arcBoxQuery.setAreaNo(archiveArchArea.getArchAreaNo());
                        //通过cabinetId查询cabinetNo
                        ArchiveCabinet archiveCabinet = archiveCabinetService.selectArchiveCabinetById(cabinet.getCabinetId());
                        //判空
                        if (ObjectUtil.isNull(archiveCabinet)) {
                            log.info("未查询到档案柜标识" + cabinet.getCabinetId() + "信息,请检查下发数据是否正确！");
                            throw new ServiceException("未查询到档案柜标识" + cabinet.getCabinetId() + "信息，请检查下发数据是否正确！");
                        }
                        arcBoxQuery.setCabinetNo(archiveCabinet.getColNo());

                        List<ArcBox> arcBoxList = arcBoxService.selectArcBoxList(arcBoxQuery);
                        if (arcBoxList.size() > 0) {
                            //循环插入盘点档案盒
                            for (ArcBox arcBox : arcBoxList) {
                                ArchiveStocktakingBox archiveStocktakingBox = new ArchiveStocktakingBox();
                                archiveStocktakingBox.setId(UUID.randomUUID().toString().replace("-", ""));
                                archiveStocktakingBox.setTaskId(archiveStocktakingTask.getTaskId());
                                archiveStocktakingBox.setArchAreaNo(archiveArchArea.getArchAreaNo());
                                archiveStocktakingBox.setColNo(archiveCabinet.getColNo());
                                archiveStocktakingBox.setBoxBarCode(arcBox.getBoxRfid());
                                archiveStocktakingBox.setBoxNo(arcBox.getBoxCode());
                                archiveStocktakingBox.setRoomNo(roomNo);
                                archiveStocktakingBox.setHouseLocationNo(arcBox.getHouseLocationNo());
                                //是否错位
                                archiveStocktakingBox.setMissStatus(BusinessConstants.NO_MISS_STATUS);
                                //是否盘盈件
                                //盘点结果
                                archiveStocktakingBox.setInventoryResult(BusinessConstants.INVENTORY_RESULT_EQUAL);
                                archiveStocktakingBox.setAddStatus(BusinessConstants.NO_ADD_STATUS);
                                //archiveStocktakingBoxService.insertArchiveStocktakingBox(archiveStocktakingBox);

                                //根据盒子查档案列表，并加入盘点档案表
                                List<RoomArchive> archiveList = roomArchiveService.selectRoomArchiveList(new RoomArchive() {{
                                    setBoxNo(arcBox.getBoxCode());
                                }});
                                for (RoomArchive roomArchive : archiveList) {
                                    ArchiveStocktaking archiveStocktaking = new ArchiveStocktaking();
                                    archiveStocktaking.setId(UUID.randomUUID().toString().replace("-", ""));
                                    archiveStocktaking.setTaskId(archiveStocktakingTask.getTaskId());
                                    archiveStocktaking.setTaskBoxId(archiveStocktakingBox.getId());
                                    archiveStocktaking.setBoxNo(arcBox.getBoxCode());
                                    archiveStocktaking.setArchiveId(roomArchive.getId());
                                    archiveStocktaking.setArchiveName(roomArchive.getArchiveName());
                                    archiveStocktaking.setOrderNo(archiveStocktakingTask.getInventoryNo());
                                    archiveStocktaking.setAddStatus(BusinessConstants.NO_ADD_STATUS);
                                    archiveStocktaking.setBorrowStatus(roomArchive.getGiveBackStatus());
                                    archiveStocktaking.setArchiveName(roomArchive.getArchiveName());
                                    archiveStocktaking.setBorrowStatus(roomArchive.getGiveBackStatus());
                                    archiveStocktaking.setArchType(roomArchive.getArchiveType());
                                    archiveStocktaking.setArchObjType(roomArchive.getArchObjType());
                                    archiveStocktaking.setArchObjNo(roomArchive.getArchObjNo());
                                    archiveStocktaking.setArchObjName(roomArchive.getArchObjName());
                                    archiveStocktaking.setMedForm(roomArchive.getMedForm());
                                    archiveStocktaking.setKeepDur(roomArchive.getSaveDate());
                                    archiveStocktaking.setConfdLv(roomArchive.getConLevel());
                                    archiveStocktaking.setInventoryResult(BusinessConstants.INVENTORY_RESULT_EQUAL);
                                    archiveStocktakingList.add(archiveStocktaking);
                                }
                                archiveStocktakingBox.setArchiveStocktakingList(archiveStocktakingList);
                                archiveStocktakingBoxList.add(archiveStocktakingBox);
                            }
                            archiveStocktakingTask.setArchiveStocktakingBoxList(archiveStocktakingBoxList);
                        }
                    }
                }
                archiveStocktakingService.batchinsertArchiveStocktaking(archiveStocktakingList);
                archiveStocktakingBoxService.batchinsertArchiveStocktakingBox(archiveStocktakingBoxList);
            }
        } catch (ServiceException e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new ServiceException(e.getMessage());
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new ServiceException("发生未知异常，事务已回滚");
        }
    }

    /**
     * 定时上报盘点任务
     *
     * @return 结果
     */
    @Override
    public ResultEntity timingArchiveStocktakingTaskResultReport() {
        //查询需要上报的任务内容
        List<ArchiveStocktakingTask> archiveStocktakingTaskList = archiveStocktakingTaskMapper.selectArchiveStocktakingTaskList(new ArchiveStocktakingTask() {{
            setPushStatus(BusinessConstants.PUSHSTATUS);
        }});
        if (archiveStocktakingTaskList.size() > 0) {
            for (ArchiveStocktakingTask archiveStocktakingTask : archiveStocktakingTaskList) {
                try {
                    archiveStocktakingTaskResultReport(archiveStocktakingTask);
                } catch (URISyntaxException e) {
                    e.printStackTrace();
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }
            }
        }

        return ResultEntity.success();
    }
}
